//
// Created by Sugars Mac on 2020/5/25.
//

#include <stdio.h>
#include <stdlib.h>     // exit
#include <string.h>
#include <unistd.h>     // bind listen
#include <time.h>       // time(NULL)   ctime(&ticks)
#include <netinet/in.h>
#include <arpa/inet.h>  // inet_ntop
#include <pthread.h>


#define PORT 8000
#define MAXMEM 10   // 最大连接数
#define BUFFSIZE 128

//#define DEBUG_PRINT 1
#ifdef DEBUG_PRINT
#define DEBUG(format, ...) printf("FILE: "__FILE__", LINE: %d: "format"\n", __LINE__, ##__VA_ARGS__)
#else
#define DEBUG(format, ...)
#endif


int listenfd, connfd[MAXMEM];

void quit();
void rcv_snd(int p);

int main()
{
    struct sockaddr_in serv_addr, cli_addr;
//      int len = sizeof(cli_addr), i;
    int i;
    time_t ticks;
    pthread_t thread;
    char buff[BUFFSIZE];

    printf("running...\n(Prompt: enter command ""quit"" to exit server)\n");
    DEBUG("=== initialize...");     //
    bzero(&serv_addr, sizeof(struct sockaddr_in));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    DEBUG("=== socket..."); //
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if(listenfd < 0)
    {
        perror("fail to socket");
        exit(-1);
    }

    DEBUG("=== bind...");   //
    if(bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
        perror("fail to bind");
        exit(-2);
    }

    DEBUG("=== listening..."); //
    listen(listenfd, MAXMEM);

    pthread_create(&thread, NULL, (void *)(quit), NULL);

    for(i=0; i<MAXMEM; i++)
        connfd[i] = -1;

    while(1)
    {
        int len;// = sizeof(cli_addr);
        for(i=0; i<MAXMEM; i++)
        {
            if(connfd[i] == -1)
                break;
        }
        if(i == MAXMEM){ // 未找到空闲的描述符位置
            continue;
        }
        // accept
        connfd[i] = accept(listenfd, (struct sockaddr *)&cli_addr, &len);
        if(connfd[i] < 0)
        {
            perror("fail to accept");
            //      continue;
        }
        ticks = time(NULL);
        //sprintf(buff, "%.24s\r\n", ctime(&ticks));
        printf("%.24s\n\tconnect from: %s, port %d\n",
               ctime(&ticks), inet_ntop(AF_INET, &(cli_addr.sin_addr), buff, BUFFSIZE),
               ntohs(cli_addr.sin_port));      // inet_ntop #include <arpa/inet.h>

        pthread_create(malloc(sizeof(pthread_t)), NULL, (void *)(&rcv_snd), (void *)i);
    }
    return 0;
}

void quit()
{
    char msg[10];
    while(1)
    {
        scanf("%s", msg);       //
        if(strcmp(msg, "quit") == 0)
        {
            printf("Byebye... \n");
            close(listenfd);
            exit(0);
        }
    }
}

void rcv_snd(int n)
{
    int len, i;
    char name[32], mytime[32], buf[BUFFSIZE];
    time_t ticks;
    int ret;

    //
    write(connfd[n], "your name: ", strlen("your name: "));
    len = read(connfd[n], name, 32);
    if(len > 0)
        name[len-1] = '\0';     //
    strcpy(buf, name);
    strcat(buf, "\tjoin in\n\0");
    //
    for(i=0; i<MAXMEM; i++)
    {
        if(connfd[i] != -1)
            write(connfd[i], buf, strlen(buf)); // 给每一个客户端都发送消息
    }

    while(1)
    {
        char temp[BUFFSIZE];
        if((len=read(connfd[n], temp, BUFFSIZE)) > 0)
        {
            temp[len-1] = '\0';
            //
            if(strcmp(temp, "bye") == 0)
            {
                close(connfd[n]);
                connfd[n] = -1;
                pthread_exit(&ret);
            }
            ticks = time(NULL);
            sprintf(mytime, "%.24s\r\n", ctime(&ticks));
            //write(connfd[n], mytime, strlen(mytime));
            strcpy(buf, name);
            strcat(buf, "\t");
            strcat(buf, mytime);
            strcat(buf, "\r\t");
            strcat(buf, temp);
            strcat(buf, "\n");

            for(i=0; i<MAXMEM; i++)
            {
                if(connfd[i] != -1)
                    write(connfd[i], buf, strlen(buf)); // 群发
            }
        }
    }
}
